package com.senriot.quickup.repository

import com.querydsl.core.types.dsl.StringPath
import com.senriot.cloud.common.IRepository
import com.senriot.quickup.domain.QUser
import com.senriot.quickup.domain.User
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.EntityGraph
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer
import org.springframework.data.querydsl.binding.QuerydslBindings
import org.springframework.stereotype.Repository
import java.time.Instant
import java.util.*


/**
 * Spring Data JPA repository for the [User] entity.
 */
@Repository
interface UserRepository : IRepository<User, Long>, QuerydslBinderCustomizer<QUser>
{

    fun findOneByActivationKey(activationKey: String): Optional<User>

    fun findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(dateTime: Instant): List<User>

    fun findOneByResetKey(resetKey: String): Optional<User>

    fun findOneByEmailIgnoreCase(email: String?): Optional<User>

    fun findOneByLogin(login: String): Optional<User>

    @EntityGraph(attributePaths = ["authorities"])
    fun findOneWithAuthoritiesById(id: Long): Optional<User>

    @EntityGraph(attributePaths = ["authorities"])
    fun findOneWithAuthoritiesByLogin(login: String): Optional<User>

    @EntityGraph(attributePaths = ["authorities"])
    fun findOneWithAuthoritiesByEmailIgnoreCase(email: String): Optional<User>

    fun findAllByLoginNot(pageable: Pageable, login: String): Page<User>

    @JvmDefault
    override fun customize(bindings: QuerydslBindings, root: QUser)
    {
        bindings.bind(String::class.java).first { path: StringPath, value: String -> path.containsIgnoreCase(value) }
        bindings.bind(root.createdDate).all { path, value ->
            if (value.size == 1)
            {
                Optional.of(path.eq(value.first()))
            } else
            {
                Optional.of(path.between(value.first().toLocalDate().atStartOfDay(),
                        value.last().toLocalDate().atStartOfDay()))
            }
        }
        bindings.excluding(root.createdBy, root.lastModifiedBy, root.lastModifiedDate)
    }
}
